package service

import (
	"bytes"
	"crypto/md5"
	"crypto/tls"
	"encoding/hex"
	"encoding/json"
	"encoding/xml"
	"errors"
	"fmt"
	"git.inedcn.com/ined/cmn"
	"io/ioutil"
	"math/rand"
	"net/http"
	"rongyy/src/helper"
	"rongyy/src/middlewares"
	"rongyy/src/models"
	"sort"
	"strconv"
	"strings"
	"time"
)

type TianfuService struct {
}

func (us *TianfuService) GetUserInfo(req *models.TfReq) (*models.CardModel, error) {
	// 先用token去换信息
	uri := "https://tfsmy.chengdu.gov.cn/api/oauth/token?client_id=4b12a408bd&client_secret=42d135acaa6045f4a8a29ed9&grant_type=authorization_code&redirect_uri=https://weixin.phcc120.com&code=" + req.Code
	respToken, err := helper.Get(uri)
	respTokenA := &models.TfTokenResp{}
	fmt.Println(string(respToken))
	err = json.Unmarshal(respToken, respTokenA)

	token := respTokenA.AccessToken
	if token == "" {
		return nil, fmt.Errorf("token获取错误")
	}

	// 用token去换信息
	//uri2 := "https://phr.care4u.cn/citizen-api/getUserInfo.do?token=" + token + "&dkey=c450829886&dcode=EFGT49DFMEG3T2U&hcode=450829886"
	uri2 := "https://tfsmy.chengdu.gov.cn/api/v2/user/identity/" + respTokenA.User + "?access_token=" + token + ""
	user := &models.User{}
	resp, err := helper.PostJson(uri2, user)
	add := &models.TianFuResp{}

	err = json.Unmarshal(resp, add)
	if err != nil {
		return nil, err
	}

	if !add.Success {
		return nil, fmt.Errorf(add.ErrorMessage)
	}
	idNo := add.Data.Idcard
	data, has, err := (&models.CardModel{}).FindCardByIDM(idNo)
	if len(data.IdNo) > 15 {
		data.Mobile = data.Mobile[0:3] + "****" + data.Mobile[7:]
		data.IdNo = data.IdNo[0:3] + "***********" + data.IdNo[14:]
	}
	if err != nil {
		middlewares.Logger.Println("UserWxInfo ", err)
		return nil, err
	}
	dob := helper.GetBirthday(idNo)
	if has {
		return data, nil
	}
	//{"age":"35","unionid":"odyfXw4fxI0LyNHkBmAFp5EYJEq4","wxid":94576,"patient_name":"吴剑龙","id_no":"510108198806240031","sex":"男","dob":"19880624","mobile":"18140245903","job":"国家公务员","marital_status":"10","address":"成都市成华区东风路18号14栋1单元5楼503号","contact_name":"","contact_id_no":"","contact_tel_no":"","id_type":"01"}
	CreateReq := &models.EcardCreateReq{
		Age:           "",
		Unionid:       req.UnionId,
		Wxid:          req.Wxid,
		PatientName:   add.Data.Name,
		IdNo:          add.Data.Idcard,
		Sex:           "",
		Dob:           dob,
		Mobile:        add.Data.Mobile,
		Job:           "",
		MaritalStatus: "",
		Address:       "",
		HospitalCode:  "",
		ContactName:   "",
		ContactTelNo:  "",
		ContactIDNo:   "",
		IdType:        "01",
		Nation:        "",
	}
	// 如果没有就去his建卡
	err = (&PatientCardService{}).CreateCardTf(CreateReq)
	if err != nil {
		return nil, fmt.Errorf("建卡失败，请重试")
	}
	data, has, err = (&models.CardModel{}).FindCardByIDM(idNo)
	return data, nil
}

func (pc *TianfuService) PayTfRegister(req *models.RegisterModel, ip string) (string, string, string, string, error) {
	data, has, err := (&models.RegisterModel{}).FindByTransactionId(req.TransactionId)
	if !has {
		return "", "", "", "", errors.New("订单不存在")
	}
	//// 查看订单是否超时
	current := time.Now().Format("2006-01-02 15:04:05")
	currentT, err := time.Parse("2006-01-02 15:04:05", current)
	if err != nil {

	}
	regTime, _ := time.Parse("2006-01-02 15:04:05", data.CreatedAt.String())
	if (currentT.Unix() - regTime.Unix()) > 610 {
		return "", "", "", "", errors.New("订单已超时，请重新挂号")
	}

	if data.Status != "locked" {
		return "", "", "", "", errors.New("订单状态错误")
	}
	if data.PayStatus == "paying" || data.PayStatus == "paid" {
		return "", "", "", "", errors.New("订单状态错误")
	}

	rand.Seed(time.Now().UnixNano())
	t := rand.Intn(10000)
	ts := strconv.FormatInt(time.Now().UnixMicro(), 10)
	orderSn := "TF" + ts + strconv.Itoa(t)
	fee, err := strconv.ParseFloat(data.Fee, 10)
	feeyuan := fee * 100
	//先入库
	reg := &models.RegisterModel{
		OrderSn:       orderSn,
		RegInfo:       models.RegInfo{},
		LockInfo:      models.LockInfo{},
		PayStatus:     "paying",
		CreatedAt:     cmn.JsonTime{},
		UpdatedAt:     cmn.JsonTime{},
		TransactionId: req.TransactionId,
		//Openid:        req.Openid,
	}
	middlewares.Logger.Println("reg.Paying 入参===", reg)
	err = reg.Paying()
	if err != nil {
		middlewares.Logger.Println("挂号支付中入库错误 failed ", err)
		return "", "", "", "", err
	}
	reqPay := &models.TfPayReq{
		OrderNo:  orderSn,
		ScIp:     ip,
		TotalFee: strconv.FormatFloat(feeyuan, 'f', -1, 64),
	}
	url1, url2, xml, err := (&TianfuService{}).UnifiedorderPay(reqPay)
	if err != nil {
		middlewares.Logger.Println("银行调用支付返回失败1", err)
		return "", "", "", "", err
	}
	return url1, url2, orderSn, xml, err
}

func WXmd5Sign(req *models.TfPayReq) (sign string) {
	str := "appid=wx20a0569be221aa8c&body=挂号费&mch_id=1427729702&nonce_str=1add1a30ac87aa2db72f57a2375d8fec&notify_url=https://weixin.phcc120.com&out_trade_no=" + req.OrderNo + "&spbill_create_ip=" + req.ScIp + "&total_fee=" + req.TotalFee + "&trade_type=MWEB&key=CHENGdushi211018CHENGdushi211018"
	hstr := md5.Sum([]byte(str))
	sum := fmt.Sprintf("%x", hstr)
	sign = strings.ToUpper(sum)

	return sign
}

func (us *TianfuService) UnifiedorderPay(req *models.TfPayReq) (string, string, string, error) {
	sign := WXmd5Sign(req)
	fmt.Println(sign)
	xmlstr := `<xml>` +
		`<appid>wx20a0569be221aa8c</appid>` +
		`<body>挂号费</body>` +
		`<mch_id>1427729702</mch_id>` +
		`<nonce_str>1add1a30ac87aa2db72f57a2375d8fec</nonce_str>` +
		`<notify_url>https://weixin.phcc120.com</notify_url>` +
		`<out_trade_no>` + req.OrderNo + `</out_trade_no>` +
		`<spbill_create_ip>` + req.ScIp + `</spbill_create_ip>` +
		`<total_fee>` + req.TotalFee + `</total_fee>` +
		`<trade_type>MWEB</trade_type>` +
		`<sign>` + sign + `</sign>` +
		`</xml>`
	fmt.Println(xmlstr)
	uri := "https://api.mch.weixin.qq.com/pay/unifiedorder"
	resp, err := helper.PostXmlJson(uri, xmlstr)
	if err != nil {
		return "", "", string(resp), err
	}

	reply := &models.WXOrderReply{}
	err = xml.Unmarshal(resp, &reply)
	if err != nil {
		return "", "", string(resp), err
	}

	if reply.ReturnCode == "SUCCESS" && reply.ResultCode == "SUCCESS" {
		return reply.PrepayID, reply.MwebURL, string(resp), nil
	}
	return "", "", string(resp), err
}

// 退款
const refundTradeUrl = "https://api.mch.weixin.qq.com/secapi/pay/refund"

type RefundTradeParam struct {
	XMLName     xml.Name `xml:"xml" json:"-"`
	AppId       string   `json:"appid" xml:"appid"`
	MchId       string   `json:"mch_id" xml:"mch_id"`
	NonceStr    string   `json:"nonce_str" xml:"nonce_str"`
	OutTradeNo  string   `json:"out_trade_no" xml:"out_trade_no"`
	OutRefundNo string   `json:"out_refund_no" xml:"out_refund_no"`
	TotalFee    string   `json:"total_fee" xml:"total_fee"`
	RefundFee   string   `json:"refund_fee" xml:"refund_fee"`
	Sign        string   `json:"sign" xml:"sign"`
}
type RefundTradeResponse struct {
	XMLName           xml.Name `xml:"xml" json:"-"`
	ReturnCode        string   `json:"return_code" xml:"return_code"`
	ReturnMsg         string   `json:"return_msg" xml:"return_msg"`
	AppId             string   `json:"appid" xml:"appid"`
	MchId             string   `json:"mch_id" xml:"mch_id"`
	NonceStr          string   `json:"nonce_str" xml:"nonce_str"`
	Sign              string   `json:"sign" xml:"sign"`
	ResultCode        string   `json:"result_code" xml:"result_code"`
	TransactionId     string   `json:"transaction_id" xml:"transaction_id"`
	OutTradeNo        string   `json:"out_trade_no" xml:"out_trade_no"`
	OutRefundNo       string   `json:"out_refund_no" xml:"out_refund_no"`
	RefundId          string   `json:"refund_id" xml:"refund_id"`
	RefundChannel     string   `json:"refund_channel" xml:"refund_channel"`
	RefundFee         string   `json:"refund_fee" xml:"refund_fee"`
	CouponRefundFee   string   `json:"coupon_refund_fee" xml:"coupon_refund_fee"`
	TotalFee          string   `json:"total_fee" xml:"total_fee"`
	CashFee           string   `json:"cash_fee" xml:"cash_fee"`
	CouponRefundCount string   `json:"coupon_refund_count" xml:"coupon_refund_count"`
	CashRefundFee     string   `json:"cash_refund_fee" xml:"cash_refund_fee"`
}

// 支付字符串拼接
func getSortString(m map[string]string) string {
	var buf bytes.Buffer
	keys := make([]string, 0, len(m))
	for k := range m {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	for _, k := range keys {
		vs := m[k]
		if vs == "" {
			continue
		}
		if buf.Len() > 0 {
			buf.WriteByte('&')
		}
		buf.WriteString(k)
		buf.WriteByte('=')
		buf.WriteString(vs)
	}
	return buf.String()
}

// 验证签名
func checkMd5Sign(rspMap map[string]string, md5Key, sign string) bool {
	calculateSign := getMd5Sign(rspMap, md5Key)
	//fmt.Println(calculateSign, sign, md5Key)
	return calculateSign == sign
}

// MD5加密
func hashaMd5(str string) string {
	h := md5.New()
	h.Write([]byte(str))
	cipherStr := h.Sum(nil)
	return hex.EncodeToString(cipherStr)
}

func getMd5Sign(paramMap map[string]string, signKey string) string {
	sortString := getSortString(paramMap)
	fmt.Println("sortString", sortString)
	sign := hashaMd5(sortString + "&key=" + signKey)
	return strings.ToUpper(sign)
}

// 申请退款
func (us *TianfuService) RefundTrade(orderId string, fee string) (trade RefundTradeResponse, err error) {
	amount, _ := strconv.ParseFloat(fee, 64)
	amount = amount * 100
	md5key := "CHENGdushi211018CHENGdushi211018"
	refundTradeMap := make(map[string]string)
	refundTradeMap["appid"] = "wx20a0569be221aa8c"
	refundTradeMap["mch_id"] = "1427729702"
	refundTradeMap["nonce_str"] = "1add1a30ac87aa2db72f57a2375d8fec"
	refundTradeMap["out_trade_no"] = orderId
	refundTradeMap["out_refund_no"] = orderId + "-1"
	refundTradeMap["total_fee"] = fmt.Sprintf("%v", amount)
	refundTradeMap["refund_fee"] = fmt.Sprintf("%v", amount)
	refundTradeMap["sign"] = getMd5Sign(refundTradeMap, md5key)
	refundTradeParam := RefundTradeParam{
		AppId:       refundTradeMap["appid"],
		MchId:       refundTradeMap["mch_id"],
		NonceStr:    refundTradeMap["nonce_str"],
		OutTradeNo:  refundTradeMap["out_trade_no"],
		OutRefundNo: refundTradeMap["out_refund_no"],
		TotalFee:    refundTradeMap["total_fee"],
		RefundFee:   refundTradeMap["refund_fee"],
		Sign:        refundTradeMap["sign"],
	}
	marshal, err := xml.Marshal(refundTradeParam)
	if err != nil {
		return trade, err
	}

	request, err := http.NewRequest(http.MethodPost, refundTradeUrl, bytes.NewReader(marshal))
	if err != nil {
		return trade, err
	}
	certFile := "src/service/cert/apiclient_cert.pem" // 商户证书
	keyFile := "src/service/cert/apiclient_key.pem"   // 商户证书
	var cliCrt tls.Certificate                        // 具体的证书加载对象
	cliCrt, err = tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		return trade, err
	}
	client := http.Client{
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{Certificates: []tls.Certificate{cliCrt}},
		},
	}
	response, err := client.Do(request)
	if err != nil {
		return trade, err
	}
	defer response.Body.Close()
	bodyBytes, err := ioutil.ReadAll(response.Body)

	if err != nil {
		return trade, err
	}
	if err = xml.Unmarshal(bodyBytes, &trade); err != nil {
		return trade, err
	}

	RefundTradeResMap := make(map[string]string)
	RefundTradeResMap["return_code"] = trade.ReturnCode
	RefundTradeResMap["return_msg"] = trade.ReturnMsg
	RefundTradeResMap["appid"] = trade.AppId
	RefundTradeResMap["mch_id"] = trade.MchId
	RefundTradeResMap["nonce_str"] = trade.NonceStr
	RefundTradeResMap["result_code"] = trade.ResultCode
	RefundTradeResMap["transaction_id"] = trade.TransactionId
	RefundTradeResMap["out_trade_no"] = trade.OutTradeNo
	RefundTradeResMap["out_refund_no"] = trade.OutRefundNo
	RefundTradeResMap["refund_id"] = trade.RefundId
	RefundTradeResMap["refund_channel"] = trade.RefundChannel
	RefundTradeResMap["refund_fee"] = trade.RefundFee
	RefundTradeResMap["coupon_refund_fee"] = trade.CouponRefundFee
	RefundTradeResMap["total_fee"] = trade.TotalFee
	RefundTradeResMap["cash_fee"] = trade.CashFee
	RefundTradeResMap["coupon_refund_count"] = trade.CouponRefundCount
	RefundTradeResMap["cash_refund_fee"] = trade.CashRefundFee

	//// 签名校验
	//if !checkMd5Sign(RefundTradeResMap, md5key, trade.Sign) {
	//	return trade, errors.New("refund trade sign verify error")
	//}
	return trade, nil
}
func WXmd5SignQuery(req *models.TfPayReq) (sign string) {
	str := "appid=wx20a0569be221aa8c&mch_id=1427729702&nonce_str=1add1a30ac87aa2db72f57a2375d8fec&out_trade_no=" + req.OrderNo + "&key=CHENGdushi211018CHENGdushi211018"
	hstr := md5.Sum([]byte(str))
	sum := fmt.Sprintf("%x", hstr)
	sign = strings.ToUpper(sum)

	return sign
}

//
//func (pc *TianfuService) orderQuery(req *models.RegisterModel, ip string) (string, string, string, string, error) {
//	data, has, err := (&models.RegisterModel{}).FindByOrderSn(req.OrderSn)
//	if !has {
//		return "", "", "", "", errors.New("订单不存在")
//	}
//	//// 查看订单是否超时
//	current := time.Now().Format("2006-01-02 15:04:05")
//	currentT, err := time.Parse("2006-01-02 15:04:05", current)
//	if err != nil {
//
//	}
//	regTime, _ := time.Parse("2006-01-02 15:04:05", data.CreatedAt.String())
//	if (currentT.Unix() - regTime.Unix()) > 610 {
//		return "", "", "", "", errors.New("订单已超时，请重新挂号")
//	}
//
//	if data.Status != "locked" || data.PayStatus != "" {
//		return "", "", "", "", errors.New("订单状态错误")
//	}
//
//	rand.Seed(time.Now().UnixNano())
//	t := rand.Intn(10000)
//	ts := strconv.FormatInt(time.Now().UnixMicro(), 10)
//	orderSn := "TF" + ts + strconv.Itoa(t)
//	//fee, err := strconv.ParseFloat(data.Fee, 10)
//
//	//先入库
//	reg := &models.RegisterModel{
//		OrderSn:       orderSn,
//		RegInfo:       models.RegInfo{},
//		LockInfo:      models.LockInfo{},
//		PayStatus:     "paying",
//		CreatedAt:     cmn.JsonTime{},
//		UpdatedAt:     cmn.JsonTime{},
//		TransactionId: req.TransactionId,
//		//Openid:        req.Openid,
//	}
//	middlewares.Logger.Println("reg.Paying 入参===", reg)
//	err = reg.Paying()
//	if err != nil {
//		middlewares.Logger.Println("挂号支付中入库错误 failed ", err)
//		return "", "", "", "", err
//	}
//	reqPay := &models.TfPayReq{
//		OrderNo:  orderSn,
//		ScIp:     ip,
//		TotalFee: data.Fee,
//	}
//	url1, url2, xml, err := (&TianfuService{}).UnifiedorderPay(reqPay)
//	if err != nil {
//		middlewares.Logger.Println("银行调用支付返回失败1", err)
//		return "", "", "", "", err
//	}
//	return url1, url2, orderSn, xml, err
//}

func (pc *TianfuService) OrderQuery(req *models.RegisterModel, ip string) (*models.WXOrderQueryResp, error) {
	reqPay := &models.TfPayReq{
		OrderNo: req.OrderSn,
	}
	sign := WXmd5SignQuery(reqPay)
	fmt.Println(sign)
	xmlstr := `<xml>` +
		`<appid>wx20a0569be221aa8c</appid>` +
		`<mch_id>1427729702</mch_id>` +
		`<nonce_str>1add1a30ac87aa2db72f57a2375d8fec</nonce_str>` +
		`<out_trade_no>` + req.OrderSn + `</out_trade_no>` +
		`<sign>` + sign + `</sign>` +
		`</xml>`

	uri := `https://api.mch.weixin.qq.com/pay/orderquery`
	resp, err := helper.PostXmlJson(uri, xmlstr)
	if err != nil {
		return nil, err
	}

	reply := &models.WXOrderQueryResp{}
	err = xml.Unmarshal(resp, &reply)
	if err != nil {
		return nil, err
	}
	if reply.ReturnCode != "SUCCESS" || reply.ResultCode != "SUCCESS" {
		return reply, fmt.Errorf(reply.ErrCodeDes)
	}
	return reply, err
}
